// 辅助函数：深度比较对象所有键值是否相等
function isEqual(a, b) {
  if (a === b) return true

  if (Array.from(arguments).every(item => toString.call(item) === '[object Object]')) {
    const [keysA, keysB] = Array.from(arguments, item => Object.keys(item))
    if (keysA.length !== keysB.length) return false

    for (let key of keysA) {
      if (!keysB.includes(key)) return false
      if (!isEqual(a[key], b[key])) return false
    }

    return true
  } else {
    return a === b
  }
}

/**
 * 对象数组去重
 * @param  {Array} 对象数组, 必传
 * @param  {String | Function} 去重的key / 返回去重key的回调, 选传
 * @return {Array} 去重后的数组
*/
function unique(arr, iterate) {
  const type = Object.prototype.toString.call(iterate).slice(8, -1).toLowerCase()
  const iterateTypes = ['number', 'string', 'boolean', 'null', 'undefined', 'function']
  if (!Array.isArray(arr) || !iterateTypes.includes(type)) 
    return arr

  let result = []
  
  if (iterate) {
    const set = new Set()
    result = arr.filter((item, index) => {
      const key = type === 'function' ? iterate(item, index, arr) : item[iterate];
      const isRepeat = set.has(key)
      set.add(key)
      return !isRepeat
    })
  } else {
    arr.forEach((item) => {
      if (!result.some(s => isEqual(s,item))) 
        result.push(item)
    }) 
  }

  return result
}


// // 测试
//  const arr = [
//   { name: '张三', age: 18, gender: 'male' }, 
//   { name: '李四', age: 20, gender: 'female' },
//   { name: '王五',  age: 18, gender: 'male' },
//   { age: 18, name: '王五',  gender: 'male' },
//  ];
//  let arr1 = unique(arr);
// //  [
// //   { name: '张三', age: 18, gender: 'male' },
// //   { name: '李四', age: 20, gender: 'female' },
// //   { name: '王五', age: 18, gender: 'male' }
// //  ]
//  let arr2 = unique(arr, 'age');
// //  [
// //   { name: '张三', age: 18, gender: 'male' },
// //   { name: '李四', age: 20, gender: 'female' }
// //  ]
//  let arr3 = unique(arr, item => item.gender);
// //  [
// //   { name: '张三', age: 18, gender: 'male' },
// //   { name: '李四', age: 20, gender: 'female' }
// //  ]
// const brr = [12, 13, 14, 12, 15]
// let brr1 = unique(brr)
// // [ 12, 13, 14, 15 ]
